import { ElMessage } from 'element-plus'
import { commonConfig } from './config.js'

/**
 * 左侧字符串转数组, 默认以逗号分割
 * @param leftStr
 * @return {{leftStr, splitArr: (void|*)}}
 */
export function leftStr2ArrWithDefaultSeparator (leftStr) {
  return leftStr2Arr(leftStr, ',')
}

// 左侧字符串转数组
export function leftStr2Arr (leftStr, separator) {
  // 前置处理，去掉空格，换行，制表符
  leftStr = preSplit(leftStr, separator)
  const splitArr = str2Arr(leftStr, separator)
  return { leftStr, splitArr }
}

function preSplit (leftStr, separator) {
  if (leftStr === '') {
    ElMessage.error('请输入要转换的列或者sql语句')
  }
  if (separator !== '') {
    leftStr = leftStr.replaceAll(separator, '\n')
  }
  return leftStr.replaceAll('\r\n', '\n')
    .replaceAll('\r', '\n')
    .replaceAll('`', '')
    .replaceAll('\n\n', '\n')
    .toLowerCase()
}

function str2Arr (leftStr, separator) {
  let splitArr = leftStr.split('\n')
  return splitArr.filter(item => {
    return item !== '' && item !== ',' && item !== separator
  }).map(item => {
    return item.trim()
  })
}


/**
 * 删除最后一个逗号
 * @param str     字符串
 * @return {string} 删除最后一个逗号后的字符串
 */
export function delLastComma (str) {
  if (str == null || str === '' || str === undefined) {
    return ''
  }
  return str.substring(0, str.lastIndexOf(','))
}

/**
 * 转换驼峰命名法
 * @param column
 * @return {*}
 */
export function toCamelCase (column) {
  return column.replace(/_([a-z])/g, function (match, letter) {
    return letter.toUpperCase()
  })
}

/**
 * 复制到剪贴板
 * @param that
 * @return {Promise<void>}
 */
export async function copy2Clipboard (that) {
  try {
    await navigator.clipboard.writeText(that.rightStr)
    ElMessage.success('复制成功')
  } catch (err) {
    ElMessage.error(`复制失败${ err }`)
  }
}

export function getForeachItemStr (splitArr) {
  let resultStr = ''
  splitArr.map((item => {
    resultStr += `\t#{item.${ toCamelCase(item) }},\n`
  }))
  resultStr = `${ delLastComma(resultStr) }`
  return resultStr
}

export function getForeachStr (that) {
  that.leftStr = that.leftStr.replace('(', '').replace(')', '')
  // 分割字符串
  const { splitArr } = leftStr2Arr(that.leftStr, ',')
  let resultStr = ''
  if (splitArr.length === 1) {
    resultStr = `${ commonConfig.outForeachPrefix }\t#{item}${ commonConfig.suffix }`
  } else {
    resultStr = `${ commonConfig.inForeachPrefix }(\n${ getForeachItemStr(splitArr) }\n)${ commonConfig.suffix }`
  }
  return resultStr
}

export function strIsBlank (str) {
  return str === '' || str === null || str === undefined
}

export function formatDate (date) {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hours = String(date.getHours()).padStart(2, '0')
  const minutes = String(date.getMinutes()).padStart(2, '0')
  const seconds = String(date.getSeconds()).padStart(2, '0')

  return `${ year }-${ month }-${ day } ${ hours }:${ minutes }:${ seconds }`
}

/**
 * 驼峰首字母大写
 * @param str
 */
export function camelCaseFirstChar2Upper (str) {
  if (str.indexOf('_') !== -1) {
    str = toCamelCase(str)
  }
  let arr = str.split('')
  arr[0] = arr[0].toUpperCase()
  return arr.join('')
}

export function camelCaseFirstChar2Lower (str) {
  if (str.indexOf('_') !== -1) {
    str = toCamelCase(str)
  }
  let arr = str.split('')
  arr[0] = arr[0].toLowerCase()
  return arr.join('')
}

/**
 * 处理字段
 * @param config        配置信息
 * @param typeList      类型映射
 * @param col           字段
 * @returns {{field, camelCaseField: *, name, comment: *, type, javaType: string}}
 */
export function convertColumn (config, typeList, col) {
  // 默认类型为String
  let javaType = 'String'
  // 如果数据库定义的类型以配置的xxx开头，则设置为对应的类型
  typeList.map(item => {
    if (col.type.toUpperCase().startsWith(item.startWith.toUpperCase())) {
      javaType = item.javaType
    }
  })
  // 对于时间类型的，选用用户配置信息
  const dateTypes = ['LocalDateTime', 'LocalDate', 'Date', 'Timestamp']
  const dateCol = dateTypes.includes(javaType)
  if (dateCol) {
    javaType = config.dateType
  }
  let afterName = col.name
  if (config.fieldPrefix) {
    afterName = afterName.replace(config.fieldPrefix, '')
  }
  return {
    name: col.name,
    field: toCamelCase(afterName),
    camelCaseField: camelCaseFirstChar2Upper(afterName),
    type: col.type,
    dateCol,
    comment: col.comment.replaceAll('\'', ''),
    javaType
  }
}

/**
 * 处理entity需要引入的列
 * @param config        配置信息
 */
export function getEntityImportList (config) {
  let resultArr = []
  if (config.lombok) {
    resultArr.push('lombok.Data')
    if (config.superClass) {
      resultArr.push(`${ config.superClass }`)
    }
    resultArr.push('lombok.experimental.Accessors')
  }
  if (config.dateType === 'LocalDateTime') {
    resultArr.push('java.time.LocalDateTime')
  }
  if (config.dateType === 'LocalDate') {
    resultArr.push('java.time.LocalDate')
  }
  if (config.dateType === 'LocalTime') {
    resultArr.push('java.time.LocalTime')
  }
  if (config.dateType === 'Date') {
    resultArr.push('java.util.Date')
  }
  if (config.dateType === 'Timestamp') {
    resultArr.push('java.sql.Timestamp')
  }
  if (config.superClass) {
    resultArr.push(config.superClass)
  }
  if (config.swagger === 'knife4j') {
    resultArr.push('io.swagger.annotations.ApiModel')
    resultArr.push('io.swagger.annotations.ApiModelProperty')
  }
  if (config.page === 'mybatisPage') {
    resultArr.push('com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO')
  }
  return resultArr
}

export function getXmlData (afterConvert, dbType, prefix, suffix) {
  const primaryKey = afterConvert.primaryKey.name
  const columnList = afterConvert.columnList
  const resultMap = []
  const baseColumnArr = []
  for (let col of columnList) {
    if (col.name === primaryKey) {
      resultMap.push(`<id column="${ col.name }" property="${ col.field }"/>`)
    } else {
      resultMap.push(`<result column="${ col.name }" property="${ col.field }"/>`)
    }
    baseColumnArr.push(`${ col.name },`)
  }
  let baseColumn = baseColumnArr.join('\n\t')
  baseColumn = baseColumn.substring(0, baseColumn.length - 1)
  return {
    resultMap: resultMap.join('\n\t'),
    baseColumn,
    insertBatch: getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix),
    updateBatch: getUpdateBatch(dbType, afterConvert, baseColumn, prefix, suffix),
    updateByPrimaryKey: getUpdateByPrimaryKey(afterConvert)
  }
}

/**
 * 生成updateByPrimaryKey
 * @param afterConvert
 */
function getUpdateByPrimaryKey (afterConvert) {
  debugger
  const primaryKey = afterConvert.primaryKey
  const columnList = afterConvert.columnList.filter(item => {
    return item.name !== primaryKey.name
  })
  let resultStr = `update ${ afterConvert.table.tableName }\n<set>`
  columnList.forEach(item => {
    if (item.javaType !== 'String') {
      resultStr += `\n\t<if test="${ item.field } != null">\n\t\t${ item.name } = #{${ item.field }},\n\t</if>`
    } else {
      resultStr += `\n\t<if test="${ item.field } != null and ${ item.field } != ''">\n\t\t${ item.name } = #{${ item.field }},\n\t</if>`
    }
  })
  resultStr += `\n\t</set>\n\twhere ${ primaryKey.name }=#{${ primaryKey.field }}`
  return resultStr
}

export function getUpdateBatch (dbType, afterConvert, baseColumn, prefix, suffix) {
  const tableName = afterConvert.table.tableName
  const columnList = afterConvert.columnList
  switch (dbType) {
    case 'mysql':
      const mysqlInsertStr = getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix)
      let mysqlUpdateArr = []
      for (let item of columnList) {
        mysqlUpdateArr.push(`\t${ item.name }=values(${ item.name })`)
      }
      const mysqlUpdateStr = mysqlUpdateArr.join(',\n')
      return `${ mysqlInsertStr }\n\tON DUPLICATE KEY UPDATE\n${ mysqlUpdateStr }`
    case 'postgresql':
      const insertStr = getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix)
      let postgreUpdateArr = []
      for (let item of columnList) {
        postgreUpdateArr.push(`\t${ item.name }=excluded.${ item.name }`)
      }
      const postgreUpdateStr = postgreUpdateArr.join(',\n')
      return `${ insertStr }\n\tON CONFLICT (${ afterConvert.table.primaryKey })DO UPDATE SET\n${ postgreUpdateStr }`
    case 'oracle':
      let oracleUpdateArr = []
      for (let item of afterConvert.columnList) {
        oracleUpdateArr.push(`${ item.name } = #{item.${ item.field }`)
      }
      const oracleUpdateStr = oracleUpdateArr.join(',\n')
      return `begin;\n${ commonConfig.inForeachPrefix }\nupdate ${ tableName } set ${ oracleUpdateStr }\n${ commonConfig.inForeachPrefix }\ncommit;`
    default:
      return ''
  }
}

export function getInsertBatch (dbType, afterConvert, baseColumn, prefix, suffix) {
  const tableName = afterConvert.table.tableName
  switch (dbType) {
    case 'mysql':
    case 'postgresql':
      return `insert into ${tableName} (${baseColumn}) \n\t value \n\t ${getForeachStrByCols(afterConvert.columnList, prefix,suffix)}`
    case 'oracle':
      let strArr = []
      for (let item of afterConvert.columnList) {
        strArr.push(`#{item.${ item.field }}`)
      }
      const str = strArr.join(',\n\t')
      return `begin;\n${ commonConfig.inForeachPrefix }\ninsert into ${ tableName } (${ baseColumn })\nvalue\n(\n${ str }\n)\n${ commonConfig.suffix }\ncommit;`
    default:
      return ''
  }
}

export function getForeachStrByCols (columnList, prefix, suffix) {
  let strArr = []
  for (let item of columnList) {
    strArr.push(`\t\t#{item.${ item.field }}`)
  }
  const str = strArr.join(',\n')
  return `${ prefix } \n\t\t(\n ${ str }\n\t\t) \n \t\t ${ suffix }`
}
